<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import IconAudio from '@/static/icons/icon-audio.png'
import IconDocument from '@/static/icons/icon-document.png'
import IconDocx from '@/static/icons/icon-docx.png'
import IconImg from '@/static/icons/icon-img.png'
import IconNone from '@/static/icons/icon-none.png'
import IconPdf from '@/static/icons/icon-pdf.png'
import IconPpt from '@/static/icons/icon-ppt.png'
import IconVideo from '@/static/icons/icon-video.png'

import IconXsl from '@/static/icons/icon-xsl.png'
import { downloadFile, FileType, formatFileSize, getFileExtension, getFileType } from '@/utils/uploadFile'

defineOptions({
  name: 'AttachmentItem',
})

const props = withDefaults(defineProps<{
  file: AttachmentItem
  showSize?: boolean
  showDownload?: boolean
}>(), {
  showSize: true,
  showDownload: false,
})

interface AttachmentItem {
  id?: number | string
  name: string
  type?: string
  size?: number
  url: string
  thumbnailUrl?: string
}

// 页面宽度
const windowWidth = ref(0)

// 监听页面宽度变化
onMounted(() => {
  // 获取系统信息
  const sysInfo = uni.getSystemInfoSync()
  windowWidth.value = sysInfo.windowWidth

  // 监听窗口大小变化（仅H5平台支持）
  // #ifdef H5
  window.addEventListener('resize', () => {
    windowWidth.value = window.innerWidth
  })
  // #endif
})

// 根据页面宽度动态计算文件名最大显示长度
const dynamicMaxLength = computed(() => {
  const width = windowWidth.value
  // 宽度阈值，单位：px
  if (width < 375) {
    // 窄屏设备
    return 15
  }
  else if (width < 768) {
    // 中等屏幕设备
    return 20
  }
  else {
    // 宽屏设备
    return 30
  }
})

// 根据文件后缀名获取对应的显示图标
function getFileIcon(item: AttachmentItem): string {
  const ext = getFileType(item.name)
  switch (ext) {
    case FileType.PDF:
      return IconPdf
    case FileType.DOC:
      return IconDocx
    case FileType.XLS:
      return IconXsl
    case FileType.PPT:
      return IconPpt
    case FileType.VIDEO:
      return IconVideo
    case FileType.IMAGE:
      return item.url || IconImg
    case FileType.DOCUMENT:
      return IconDocument
    case FileType.AUDIO:
      return IconAudio
    default:
      return IconNone
  }
}

// 计算字符串的视觉长度（汉字算2个字符，英文数字算1个字符）
function getVisualLength(str: string): number {
  let length = 0
  for (let i = 0; i < str.length; i++) {
    // 判断是否为汉字或全角字符
    const char = str.charCodeAt(i)
    // 汉字、全角符号等的Unicode范围
    if ((char >= 0x4E00 && char <= 0x9FA5) || (char >= 0xFF00 && char <= 0xFFEF)) {
      length += 2
    }
    else {
      length += 1
    }
  }
  return length
}

// 格式化文件名，过长时显示开头和结尾，中间用...替代
function formatFileName(name: string, maxLength?: number): string {
  // 使用动态计算的长度或传入的长度
  const maxVisualLength = maxLength || dynamicMaxLength.value

  // 计算文件名的视觉长度
  const visualLength = getVisualLength(name)

  // 如果视觉长度小于等于最大长度，直接返回
  if (!name || visualLength <= maxVisualLength) {
    return name
  }

  // 获取文件扩展名
  const lastDotIndex = name.lastIndexOf('.')
  let fileName = name
  let ext = ''

  if (lastDotIndex !== -1) {
    fileName = name.slice(0, lastDotIndex)
    ext = name.slice(lastDotIndex)
  }

  // 调整最大长度，减去扩展名的视觉长度
  const extVisualLength = getVisualLength(ext)
  const adjustedMaxVisualLength = maxVisualLength - extVisualLength

  // 如果文件名视觉长度小于等于调整后的最大长度，直接返回
  if (getVisualLength(fileName) <= adjustedMaxVisualLength) {
    return name
  }

  // 计算前缀和后缀的视觉长度
  const prefixVisualLength = Math.ceil(adjustedMaxVisualLength / 2) - 1
  const suffixVisualLength = adjustedMaxVisualLength - prefixVisualLength - 3 // 减去3个省略号的视觉长度（...算3个字符）

  // 截取前缀
  let prefix = ''
  let currentVisualLength = 0
  for (let i = 0; i < fileName.length; i++) {
    const char = fileName[i]
    const charVisualLength = getVisualLength(char)
    if (currentVisualLength + charVisualLength > prefixVisualLength) {
      break
    }
    prefix += char
    currentVisualLength += charVisualLength
  }

  // 截取后缀
  let suffix = ''
  currentVisualLength = 0
  for (let i = fileName.length - 1; i >= 0; i--) {
    const char = fileName[i]
    const charVisualLength = getVisualLength(char)
    if (currentVisualLength + charVisualLength > suffixVisualLength) {
      break
    }
    suffix = char + suffix
    currentVisualLength += charVisualLength
  }

  // 生成最终文件名
  return `${prefix}...${suffix}${ext}`
}

// 打开预览
function openPreview(item: AttachmentItem) {
  const fileType = getFileType(item.name)

  if (fileType === 'image') {
    uni.previewImage({
      urls: [item.url],
      current: item.url,
    })
  }
  else {
    // 下载文档
    previewDocument(item) // 传递true表示下载后需要预览
  }
}

// 文档预览函数
function previewDocument(item: AttachmentItem) {
  uni.showLoading({ title: '加载中...' })

  uni.downloadFile({
    url: item.url,
    success: (res) => {
      if (res.statusCode === 200) {
        uni.openDocument({
          filePath: res.tempFilePath,
          showMenu: true,
          success: () => {
            uni.hideLoading()
            console.log('文档预览成功:', item.name)
          },
          fail: (err) => {
            uni.hideLoading()
            console.error('文档预览失败:', err)
            uni.showToast({
              title: '文档打开失败',
              icon: 'none',
            })
          },
        })
      }
      else {
        uni.hideLoading()
        uni.showToast({
          title: '文件下载失败',
          icon: 'none',
        })
      }
    },
    fail: (err) => {
      uni.hideLoading()
      console.error('文件下载失败:', err)
      uni.showToast({
        title: '文件下载失败',
        icon: 'none',
      })
    },
  })
}
</script>

<template>
  <view class="relative mb-2.5 w-full flex items-center gap-3 rounded-lg bg-#fafafa p-3 shadow-md">
    <!-- 左侧：图标/预览图 -->
    <view class="h-15 w-10 flex items-center justify-center">
      <!-- 图片显示预览图 -->
      <image
        :src="getFileIcon(props.file)"
        class="h-full w-full"
        mode="aspectFit"
        :lazy-load="true"
      />
    </view>

    <!-- 中间：文件信息 -->
    <view class="min-w-0 flex-1 overflow-hidden">
      <!-- 文件名（超出显示省略号） -->
      <text class="mb-1 block overflow-hidden whitespace-nowrap text-base text-gray-800 font-medium text-ellipsis">{{ formatFileName(props.file.name, 25) }}</text>
      <!-- 类型和文件大小 -->
      <view class="flex items-center gap-2">
        <text class="rounded bg-gray-100 px-1.5 py-0.5 text-xs text-gray-600">
          {{ getFileExtension(props.file.name) }}
        </text>
        <text v-if="showSize" class="text-xs text-gray-500">
          {{ formatFileSize(12983) }}
        </text>
      </view>
    </view>

    <!-- 右侧：操作图标 -->
    <view class="attachment-actions flex items-center gap-2">
      <!-- 预览按钮（图片） -->
      <view
        class="action-btn h-9 w-9 flex cursor-pointer items-center justify-center rounded-full bg-blue-50 transition-all duration-200 active:scale-95 hover:scale-105"
        @click="openPreview(props.file)"
      >
        <text class="i-solar:eye-outline text-lg text-blue-500" />
      </view>
      <!-- 下载按钮（所有文件） -->
      <view
        v-if="showDownload"
        class="action-btn h-9 w-9 flex cursor-pointer items-center justify-center rounded-full bg-green-50 transition-all duration-200 active:scale-95 hover:scale-105"
        @click="downloadFile(props.file)"
      >
        <text class="i-solar:download-outline text-lg text-green-500" />
      </view>
    </view>
  </view>
</template>

<style lang="scss" scoped>
// 所有样式已使用 unocss 类名实现
</style>
